#!/usr/bin/env python
# -*- coding: utf-8 -*-


# Copyright 2009 David Lee Miller
#
# This file is part of POSSM (Python Open Source Scanning Microscopy).
#
# POSSM is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# POSSM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License         
# along with POSSM.  If not, see <http://www.gnu.org/licenses/>.
#                                                                           
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

from client import wx,os,time,Queue,n
from client.console import ConsoleCommands
from client.pylabiv import *
from client.display import Scanning2
import client.cdfview as cdv

import shared.createtree as createtree
import shared.datatransfer as dt
import shared.worldsettings as ws
import shared.scanvariables as sv

import wx.grid
from wx.lib.mixins.grid import GridAutoEditMixin
import wx.gizmos
import cPickle
from client.editor import Editor

__author__ = 'David Lee Miller'
__version__ = ws.VERSION


def change_intensity(color, fac):
    rgb = [color.Red(), color.Green(), color.Blue()]
    for i, intensity in enumerate(rgb):
        rgb[i] = min(int(round(intensity*fac, 0)), 255)
        
    return wx.Color(*rgb)    

class LED(wx.Control):
    def __init__(self, parent, id=-1, colors=[wx.Colour(100, 10, 10), wx.Colour(220, 10, 10), wx.Colour(125, 100, 0), wx.Colour(250, 200, 0), wx.Colour(10, 125, 200), 
		 wx.Colour(10, 220, 45),wx.Colour(250, 200, 0),wx.Colour(220, 10, 10)],
                 pos=(-1,-1), style=wx.NO_BORDER):
        size = (17, 17)
        wx.Control.__init__(self, parent, id, pos, size, style)
        self.MinSize = size
        
        self._colors = colors
        self._state = -1
        self.SetState(0)
        self.Bind(wx.EVT_PAINT, self.OnPaint, self)
        
    def SetState(self, i):
        if i < 0:
            raise ValueError, 'Cannot have a negative state value.'
        elif i >= len(self._colors):
            raise IndexError, 'There is no state with an index of %d.' % i
        elif i == self._state:
            return
        
        self._state = i
	base_color = self._colors[i]
        light_color = change_intensity(base_color, 1.08)
        shadow_color = change_intensity(base_color, 1.02)
        highlight_color = change_intensity(base_color, 1.14)
        
        ascii_led = '''
        000000-----000000      
        0000---------0000
        000-----------000
        00-----XXX----=00
        0----XX**XXX-===0
        0---X***XXXXX===0
        ----X**XXXXXX====
        ---X**XXXXXXXX===
        ---XXXXXXXXXXX===
        ---XXXXXXXXXXX===
        ----XXXXXXXXX====
        0---XXXXXXXXX===0
        0---=XXXXXXX====0
        00=====XXX=====00
        000===========000
        0000=========0000
        000000=====000000
        '''.strip()
        
        xpm = ['17 17 5 1', # width height ncolors chars_per_pixel
               '0 c None', 
               'X c %s' % base_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '- c %s' % light_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '= c %s' % shadow_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '* c %s' % highlight_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii')]
        
        xpm += [s.strip() for s in ascii_led.splitlines()]
        
        self.bmp = wx.BitmapFromXPMData(xpm)
        self.Refresh()
        
    def GetState(self):
        return self._state

    State = property(GetState, SetState)
    
    def OnPaint(self, e):
        dc = wx.PaintDC(self)
        dc.DrawBitmap(self.bmp, 0, 0, True)


class MenuItems(object):
	''' Arranges the stm client menu bar. '''
	pid = os.getpid()
	def __init__(self):
		#self.CreateStatusBar()
		filemenu=wx.Menu()
		viewer = wx.MenuItem(filemenu, 21, '&cdfViewer\tCtrl+P', 'View past data.')
		viewer.SetBitmap(wx.Bitmap(ws.ICONPATH+'find.png'))
		filemenu.AppendItem(viewer)
		#filemenu.Append(21, '&Viewer', 'View past data.')
		fileopen = wx.MenuItem(filemenu, 22, '&Open\tCtrl+Q','Load an existing configuration')
		fileopen.SetBitmap(wx.Bitmap(ws.ICONPATH+'fileopen.png'))
		filemenu.AppendItem(fileopen)
		#filemenu.Append(22, '&Open', 'Open an existing document')
		save = wx.MenuItem(filemenu, 23, '&Save\tCtrl+S', 'Save your current configuration')
		save.SetBitmap(wx.Bitmap(ws.ICONPATH+'filesave.png'))
		filemenu.AppendItem(save)
		#filemenu.Append(23, '&Save', 'Save your work')
		filemenu.AppendSeparator()
		#filemenu.Append(24, '&Port', 'Set the pygame port')
		#filemenu.AppendSeparator()
		about = wx.MenuItem(filemenu, 25, '&About\tCtrl+A', 'Information about this program')
		about.SetBitmap(wx.Bitmap(ws.ICONPATH+'help-about.png'))
		filemenu.AppendItem(about)
		#filemenu.Append(25, '&About', 'Information about this program')
		filemenu.AppendSeparator()
		quit = wx.MenuItem(filemenu, 26, '&Quit\tCtrl+Q', 'Terminate the program')
		quit.SetBitmap(wx.Bitmap(ws.ICONPATH+'exit.png'))
		filemenu.AppendItem(quit)
		#filemenu.Append(26, 'E&xit', 'Terminate the program')
		menuBar = wx.MenuBar()
		menuBar.Append(filemenu, '&File')
		self.SetMenuBar(menuBar)
		wx.EVT_MENU(self, 21, self.OnView)
		wx.EVT_MENU(self, 22, self.OnOpen)
		wx.EVT_MENU(self, 23, self.OnSave)
		#wx.EVT_MENU(self, 24, self.OnPort)
		wx.EVT_MENU(self, 25, self.OnAbout)
		wx.EVT_MENU(self, 26, self.OnExit)
		
	def OnOpen(self, ev):
		'''Open a file'''
		dlg = wx.FileDialog(self, 'Choose a file', ws.BASE_DIRECTORY, '', '*.cfg', wx.OPEN)
		if dlg.ShowModal() == wx.ID_OK:
			self.filename = dlg.GetFilename()
			self.dirname = dlg.GetDirectory()
			fh=open(os.path.join(self.dirname,self.filename),'r')
			temp = cPickle.load(fh)
			for j in range(len(createtree.treelist)):
				for i in dir(temp[j]):
					if type(i)==str and not i[0:2] == "__":
						createtree.treelist[j].__setattr__('data',temp[j].data)
			self.newtree._reset()
			fh.close()
		dlg.Destroy()
	
	def OnView(self, ev):
		'''
		View Old Data.
		'''
		asdf = cdv.Scanview(self,homefrm=self)
		asdf.do_show()
	
	def OnSave(self,ev):
		'''
		Save the current configuration.
		'''
		# Save away the edited text
		# Open the file, do an RU sure check for an overwrite!
		dlg = wx.FileDialog(self, "Select a location", ws.BASE_DIRECTORY, "", "*.cfg", wx.SAVE | wx.OVERWRITE_PROMPT)
		if dlg.ShowModal() == wx.ID_OK:
			# Grab the content to be saved
			#itcontains = self.control.GetValue()
			
			# Open the file for write, write, close
			self.filename=dlg.GetFilename()
			self.dirname=dlg.GetDirectory()
			if not self.filename[:-4] == '.cfg': self.filename += '.cfg'
			fh=open(os.path.join(self.dirname, self.filename),'w')
			#filehandle.write(itcontains)
                        cPickle.dump(createtree.treelist,fh)
			fh.close()
		# Get rid of the dialog to keep things tidy
		dlg.Destroy()
	
	#def OnPort(self, ev):
		#'''
		#Changes the client side port setting.
		#'''
		#dlg = wx.TextEntryDialog(self,'Enter a port number (default %d):'%ws.PORT_PYGAME[0])
		#if os.path.exists('port.pygame'):
			#fh=open('port.pygame','r')
			#port=fh.read()
		#else: port=str(ws.PORT_PYGAME[0])
		#dlg.SetValue(port)
		#if dlg.ShowModal() == wx.ID_OK:
			#fh=open('port.pygame','w')
			#port=dlg.GetValue()
			#fh.write(port)
			#fh.close()
		#self.OnQuit(None)
		#self.pypt0 = int(port)
		#self.pypt1 = int(port)+1
		#self.pypt2 = int(port)+2
		#dlg.Destroy()
	
	def OnAbout(self, ev):
		'''
		Display information about this program.
		'''
		version = 'pySTM version %s\n'%ws.VERSION
		d = wx.MessageDialog( self, version+'by D. Lee Miller', 'About pySTM', wx.OK)
		d.ShowModal()
		d.Destroy()
	
	def OnExit(self, ev):
		'''
		Closes the program.
		'''
		if self.pid:
			os.kill(self.pid,1)
			self.pid = None
		else: pass
		self.Close(True)
		
		
class STMControl(wx.Panel, ConsoleCommands):
	''' Creates the STM control panel and functions. '''
	VOLTS_PER_ADU = ws.VOLTS_PER_ADU
	ANG_PER_VOLT_X = ws.ANG_PER_VOLT_X
	ANG_PER_VOLT_Y = ws.ANG_PER_VOLT_Y
	SCAN_GAIN = ws.SCAN_GAIN
	TOP_SPACE = 20
	stm_controllers = ws.CONTROLLERS
	last = {}
	lineN = 0
	def __init__(self, parent):
		wx.Panel.__init__(self, parent)
		self.statusBar = None
		self.panel_1 = wx.Panel(self, -1)
		self.param_tree = wx.TreeCtrl(self, -1, style=wx.TR_HAS_BUTTONS|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
		self.param_grid = wx.grid.Grid(self, -1, size=(1, 1))
		self.label_1 = wx.StaticText(self, -1, "Lines:")
		self.panel_2 = wx.Panel(self, -1)
		self.panel_4 = wx.Panel(self, -1)
		self.label_2 = wx.StaticText(self, -1, "Time Left:")
		self.panel_3 = wx.Panel(self, -1)
		self.panel_5 = wx.Panel(self, -1)
		#self.panel_6 = wx.Panel(self, -1)
		self.send_mode = wx.Button(self, -1, '>')
		self.choice_label = wx.StaticText(self, -1, "Network ID: ")
		self.stm_choice = wx.TextCtrl(self,-1,self.stm_controllers['stmb'])
		self.stm_list = wx.Choice(self, -1, choices=self.stm_controllers.keys())
		#self.stm_approach = wx.ToggleButton(self, -1, 'Manual Approach')
		self.stm_conn = wx.Button(self, -1, 'Connect')
		self.stm_dconn = wx.Button(self, -1, 'Disconnect')
		#imageFile = ws.ICONPATH+'start.png'
		#image1 = wx.Image(imageFile, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
		#self.stm_start = wx.BitmapButton(self, id=-1, bitmap=image1,pos=(10, 20), size = (image1.GetWidth()+5, image1.GetHeight()+5))
		self.stm_start = wx.Button(self, -1, 'Start (F2)')
		#imageFile = ws.ICONPATH+'stop.png'
		#image1 = wx.Image(imageFile, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
		#self.stm_abort = wx.BitmapButton(self, id=-1, bitmap=image1,pos=(10, 20), size = (image1.GetWidth()+5, image1.GetHeight()+5))
		self.stm_abort = wx.Button(self, -1, 'Abort (ESC)')
		self.stm_yes = wx.Button(self, -1, 'Yes (F3)')
		self.stm_no = wx.Button(self, -1, 'No')
		self.stm_selected = wx.StaticText(self, -1, 'Selected Scan: None')
		#self.spec_disp = wx.ToggleButton(self, -1, 'Spectroscopy Display')
		self.panel_12 = wx.Panel(self, -1)
		#self.imagebox = wx.ListBox(self, -1, choices=['No Scans Completed'])
		
		self.lineled = wx.gizmos.LEDNumberCtrl(self.panel_2, -1, size=(50, 17), style=wx.gizmos.LED_ALIGN_CENTER)
		self.timeleft = wx.gizmos.LEDNumberCtrl(self.panel_3, -1, size=(50, 17), style=wx.gizmos.LED_ALIGN_CENTER)
		self.OnTimer(None)
		self.timer = wx.Timer(self, id=102)
		self.timer.Start(1000)

		self.Bind(wx.EVT_TIMER, self.OnTimer, id=102)
		
		self.newtree = createtree.PlantTrees(self.param_tree)
		self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnExpand, self.param_tree)
		self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnExpand, self.param_tree)
		self.Bind(wx.EVT_TREE_ITEM_COLLAPSING, self.OnCollapse, self.param_tree)
		self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate, self.param_tree)
		#
		# init the console class (i.e. sets up the program's command line)
		#
		widgets = {'grid':self.param_grid,'tree':self.param_tree,'mode':self.send_mode,'yes':self.stm_yes,\
		'no':self.stm_no,'start':self.stm_start,'abort':self.stm_abort,'connect':self.stm_conn,\
		'disconnect':self.stm_dconn,'display':None}
		ConsoleCommands.__init__(self,widgets)
		#
		# Bind the buttons to function calls
		#
		self.Bind(wx.EVT_BUTTON,self.OnYes,self.stm_yes)
		self.Bind(wx.EVT_BUTTON,self.OnNo,self.stm_no)
		self.Bind(wx.EVT_BUTTON,self.OnAbort,self.stm_abort)
		self.Bind(wx.EVT_BUTTON,self.OnDcon,self.stm_dconn)
		self.Bind(wx.EVT_BUTTON,self.OnConn_b,self.stm_conn)
		self.Bind(wx.EVT_CHOICE,self.OnSTMCh,self.stm_list)
		self.Bind(wx.EVT_BUTTON,self.StartScan,self.stm_start)
		#self.Bind(wx.EVT_TOGGLEBUTTON,self.OnManApp,self.stm_approach)
		
		self.__set_properties()
		self.__do_layout()
		#print dir(self.param_grid)
		self.param_grid.SetCellHighlightColour(wx.Colour(142,205,240))
		self.param_grid.SetCellHighlightPenWidth(2)
		#self.parent.AddPage(self,"Control")
		#self.Bind(wx.EVT_LISTBOX_DCLICK, self.openIMG, self.imagebox)
		self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnChange, self.param_grid)
		#self.ShowFullScreen(True)
		#self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnGridClick, self.param_grid)

	def __set_properties(self):
		#self.SetTitle("STM Client")
		self.panel_1.SetMinSize((521, self.TOP_SPACE))
		self.param_tree.SetMinSize((265, 300))
		self.param_grid.CreateGrid(10, 3)
		self.param_grid.SetRowLabelSize(27)
		self.param_grid.SetColLabelSize(30)
		self.param_grid.EnableDragColSize(0)
		self.param_grid.EnableDragRowSize(0)
		self.param_grid.EnableDragGridSize(0)
		self.param_grid.SetGridLineColour(wx.Colour(0, 0, 0))
		self.param_grid.SetLabelBackgroundColour(wx.Colour(238, 238, 238))
		self.param_grid.SetColLabelValue(0, "Name")
		self.param_grid.SetColLabelValue(1, "Value")
		self.param_grid.SetColLabelValue(2, "Unit")
		self.param_grid.SetMinSize((306, 300))
		self.console_disp.SetMinSize((611, 185))
		self.console.SetMinSize((591, 27))
		self.send_mode.SetMinSize((20,27))
		self.label_1.SetMinSize((75, 40))
		self.panel_2.SetMinSize((75, 40))
		self.label_2.SetMinSize((75, 40))
		self.panel_3.SetMinSize((50, 40))
		#self.panel_6.SetMinSize((60, 40))
		#self.panel_9.SetMinSize((50, 140))
		self.panel_12.SetMinSize((145,40))
		#self.stm_approach.SetMinSize((150,27))
		self.stm_list.SetMinSize((150,27))
		self.stm_conn.SetMinSize((150,27))
		self.stm_dconn.SetMinSize((150,27))
		self.stm_start.SetMinSize((150,27))
		self.stm_abort.SetMinSize((150,27))
		self.stm_yes.SetMinSize((150,27))
		self.stm_no.SetMinSize((150,27))
		attr = wx.grid.GridCellAttr()
		attr.SetReadOnly(True)
		self.param_grid.SetColAttr(0, attr)
		self.param_grid.SetColAttr(2, attr)
		self.param_grid.SetColAttr(1, attr)

	def __do_layout(self):
		sizer_1 = wx.BoxSizer(wx.VERTICAL)
		grid_sizer_1 = wx.FlexGridSizer(1, 2, 0, 0)
		grid_sizer_2 = wx.FlexGridSizer(4, 2, 0, 0)
		grid_sizer_5a = wx.FlexGridSizer(2, 3, 0, 0)
		#grid_sizer_5 = wx.FlexGridSizer(2, 3, 0, 0)
		grid_sizer_3 = wx.FlexGridSizer(4, 1, 0, 0)
		grid_sizer_4 = wx.FlexGridSizer(1, 2, 0, 0)
		grid_sizer_6 = wx.FlexGridSizer(1, 2, 0, 0)
		grid_sizer_7 = wx.FlexGridSizer(1, 2, 0, 0)
		grid_sizer_3.Add(self.panel_1, 1, wx.GROW, 0)
		stypes = wx.StaticBox(self, -1, 'Scan Types')
		typesizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2d = wx.StaticBoxSizer(stypes,wx.VERTICAL)
		sizer2d.Add(self.param_tree, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		grid_sizer_4.Add(sizer2d, 1, wx.GROW|wx.ALL, 10)
		settings = wx.StaticBox(self, -1, 'Settings')
		setsizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2c = wx.StaticBoxSizer(settings,wx.VERTICAL)
		sizer2c.Add(self.param_grid, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		grid_sizer_4.Add(sizer2c, 1, wx.GROW|wx.ALL, 10)
		grid_sizer_3.Add(grid_sizer_4, 1, wx.GROW, 0)
		cstatus = wx.StaticBox(self, -1, 'Controller Status')
		cstatussizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2e = wx.StaticBoxSizer(cstatus,wx.VERTICAL)
		sizer2e.Add(self.console_disp, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		grid_sizer_3.Add(sizer2e, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.ALL, 10)
		grid_sizer_6.Add(self.send_mode, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.LEFT, 5)
		grid_sizer_6.Add(self.console, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.RIGHT, 5)
		conbox = wx.StaticBox(self, -1, 'Console')
		constatussizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2f = wx.StaticBoxSizer(conbox,wx.VERTICAL)
		sizer2f.Add(grid_sizer_6, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		grid_sizer_3.Add(sizer2f, 1, wx.GROW|wx.LEFT|wx.RIGHT, 10)
		grid_sizer_1.Add(grid_sizer_3, 1, wx.GROW, 0)
		
		
		grid_sizer_5a.Add(self.label_1, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE|wx.GROW, 5)
		grid_sizer_5a.Add(self.panel_2, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE|wx.GROW, 5)
		grid_sizer_5a.Add(self.panel_4, 1, wx.EXPAND, 0)
		grid_sizer_5a.Add(self.label_2, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE|wx.GROW, 5)
		grid_sizer_5a.Add(self.panel_3, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE|wx.GROW, 5)
		grid_sizer_5a.Add(self.panel_5, 1, wx.EXPAND|wx.GROW, 0)
		
		prog = wx.StaticBox(self, -1, 'Progress')
		progsizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2a = wx.StaticBoxSizer(prog,wx.VERTICAL)
		sizer2a.Add(grid_sizer_5a, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		
		#manapp = wx.StaticBox(self, -1, 'Manual Approach')
		#manappsizer = wx.BoxSizer(wx.HORIZONTAL)
		#sizer2h = wx.StaticBoxSizer(manapp,wx.VERTICAL)
		#sizer2h.Add(self.stm_approach, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)

		disp = wx.StaticBox(self, -1, 'Connection')
		dispsizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2b = wx.StaticBoxSizer(disp,wx.VERTICAL)
		#sizer2b.Add(self.scan_disp, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		#sizer2b.Add(self.spec_disp, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2b.Add(self.stm_list, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		grid_sizer_7.Add(self.choice_label, 0, wx.ADJUST_MINSIZE|wx.TOP|wx.LEFT, 10)
		grid_sizer_7.Add(self.stm_choice, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		sizer2b.Add(grid_sizer_7, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2b.Add(self.stm_conn, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2b.Add(self.stm_dconn, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		
		scan = wx.StaticBox(self, -1, 'Scan')
		scansizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2g = wx.StaticBoxSizer(scan,wx.VERTICAL)
		sizer2g.Add(self.stm_yes, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2g.Add(self.stm_no, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2g.Add(self.stm_selected, 0, wx.ADJUST_MINSIZE|wx.TOP|wx.CENTER, 15)
		sizer2g.Add(self.stm_start, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2g.Add(self.stm_abort, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		
		#Add Retract and Hold Buttons
		led = wx.StaticBox(self, -1, 'Hold/Retract')
		ledsizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2h = wx.StaticBoxSizer(led,wx.VERTICAL)
		sizer2h1 = wx.FlexGridSizer(2,1,0,0)
		sizer2h2 = wx.FlexGridSizer(2,2,0,0)
		holdsizer = wx.BoxSizer(wx.HORIZONTAL)
		self.l1 = LED(self)
		self.l1.State = 3
		self.hold = wx.Button(self, -1, 'H +')
		self.hold.SetMinSize((55,27))
		self.unhold = wx.Button(self, -1, 'H -')
		self.unhold.SetMinSize((55,27))
		holdsizer.Add(self.l1, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		holdsizer.Add(self.hold, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		holdsizer.Add(self.unhold, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		retsizer = wx.BoxSizer(wx.HORIZONTAL)
		self.l2 = LED(self)
		self.l2.State = 1
		self.retract = wx.Button(self, -1, 'R +')
		self.retract.SetMinSize((55,27))
		self.unretract = wx.Button(self, -1, 'R -')
		self.unretract.SetMinSize((55,27))
		retsizer.Add(self.l2, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		retsizer.Add(self.retract, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		retsizer.Add(self.unretract, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2h1.Add(holdsizer)
		sizer2h1.Add(retsizer)
		#sizer2h1.Add(self.l2, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 10)
		#sizer2h1.Add(self.retract, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2h.Add(sizer2h1, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2h2.Add(sizer2h, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.CENTER, 10)
		self.hold.Bind(wx.EVT_BUTTON,self.OnHold)
		self.unhold.Bind(wx.EVT_BUTTON,self.OnUnHold)
		self.retract.Bind(wx.EVT_BUTTON,self.OnRetract)
		self.unretract.Bind(wx.EVT_BUTTON,self.OnUnRetract)

		# Add Absolute position
		dac = wx.StaticBox(self, -1, 'DAC Voltage')
		dacsizer = wx.BoxSizer(wx.HORIZONTAL)
		sizer2i = wx.StaticBoxSizer(dac,wx.VERTICAL)
		sizer2i1 = wx.FlexGridSizer(4,1,0,0)
		sizer2i2 = wx.FlexGridSizer(1,2,0,0)
		dac1sizer = wx.BoxSizer(wx.HORIZONTAL)
		self.l3 = LED(self)
		self.l3.State = 4
		self.dac1V = wx.StaticText(self, -1, 'HG: %0.2f V'%0.0)
		self.rb1 = wx.RadioButton(self, -1, 'Active', (15, 30), style=wx.RB_GROUP)
		self.rb1.SetMinSize((75,27))
		dac1sizer.Add(self.l3, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		dac1sizer.Add(self.dac1V, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		dac1sizer.Add(self.rb1, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)

		dac2sizer = wx.BoxSizer(wx.HORIZONTAL)
		self.l4 = LED(self)
		self.l4.State = 4
		self.dac2V = wx.StaticText(self, -1, 'LG: %0.2f V '%0.0)
		self.rb2 = wx.RadioButton(self, -1, 'Inactive', (15, 30))
		self.rb2.SetMinSize((75,27))
		dac2sizer.Add(self.l4, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		dac2sizer.Add(self.dac2V, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		dac2sizer.Add(self.rb2, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		self.dacupdate = wx.Button(self, -1, 'Update')
		self.dacupdate.SetMinSize((150,27))
		#self.dacupdate.Disable()
		self.dacswap = wx.Button(self, -1, 'Swap')
		self.dacswap.SetMinSize((150,27))
		#self.dacswap.Disable()
		sizer2i1.Add(dac1sizer)
		sizer2i1.Add(dac2sizer)
		sizer2i1.Add(self.dacupdate, 0, wx.ADJUST_MINSIZE|wx.TOP|wx.CENTER, 10)
		sizer2i1.Add(self.dacswap, 0, wx.ADJUST_MINSIZE|wx.TOP|wx.CENTER, 10)
		#sizer2h1.Add(self.l2, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 10)
		#sizer2h1.Add(self.retract, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2i.Add(sizer2i1, 0, wx.ADJUST_MINSIZE|wx.ALL|wx.CENTER, 5)
		sizer2i2.Add(sizer2i, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.CENTER, 10)
		self.dacupdate.Bind(wx.EVT_BUTTON,self.OnDACUpdate)
		self.dacswap.Bind(wx.EVT_BUTTON,self.OnVSwap)
		self.Bind(wx.EVT_RADIOBUTTON, self.OnDACUpdate, id=self.rb1.GetId())
		self.Bind(wx.EVT_RADIOBUTTON, self.OnDACUpdate, id=self.rb2.GetId())
		#self.retract.Bind(wx.EVT_BUTTON,self.OnRetract)

		#PID Gain Adjustments
		limbox = wx.StaticBox(self, -1, 'PID')

		lims0=wx.BoxSizer(wx.HORIZONTAL)
		lims1=wx.BoxSizer(wx.HORIZONTAL)
		lims2=wx.BoxSizer(wx.HORIZONTAL)
		lims3=wx.BoxSizer(wx.HORIZONTAL)

		kp_l = wx.StaticText(self,-1,'KP')
		kp_l.SetMinSize((27,27))
		ki_l = wx.StaticText(self,-1,'KI')
		ki_l.SetMinSize((27,27))
		kd_l = wx.StaticText(self,-1,'KD')
		kd_l.SetMinSize((27,27))

		self.kps = wx.Slider(self, -1, 0, 0, 10, (-1, -1), (250, -1), 
		wx.SL_AUTOTICKS | wx.SL_VERTICAL | wx.SL_LABELS)
		self.kps.SetMinSize((25,127))
		self.kp = 10
		self.kps.SetValue(4)
		self.kis = wx.Slider(self, -1, 0, 0, 10, (-1, -1), (250, -1), 
		wx.SL_AUTOTICKS | wx.SL_VERTICAL | wx.SL_LABELS)
		self.kis.SetMinSize((25,127))
		self.ki = 10
		self.kis.SetValue(4)
		#ylims=wx.BoxSizer(wx.HORIZONTAL)
		self.kds = wx.Slider(self, -1, 0, 0, 10, (-1, -1), (250, -1), 
		wx.SL_AUTOTICKS | wx.SL_VERTICAL | wx.SL_LABELS)
		self.kds.SetMinSize((25,127))
		self.kd = 1
		self.kds.SetValue(0)

		decades = ['e+2','e+1','e+0','e-1','e-2','e-3','e-4','e-5','e-6']
		self.pdecade = wx.Choice(self,-1,choices=decades)
		self.pdecade.SetMinSize((60,27))
		self.pdecade.SetSelection(6)
		self.idecade = wx.Choice(self,-1,choices=decades)
		self.idecade.SetMinSize((60,27))
		self.idecade.SetSelection(6)
		self.ddecade = wx.Choice(self,-1,choices=decades)
		self.ddecade.SetMinSize((60,27))
		self.ddecade.SetSelection(6)

		self.gainapply = wx.Button(self, -1, 'Apply')
		self.gainapply.SetMinSize((68,27))

		self.stepresp = wx.ToggleButton(self, -1, 'SR Mode')
		self.stepresp.SetMinSize((68,27))

		pidhbox = wx.BoxSizer(wx.HORIZONTAL)
		pidhbox.Add(self.gainapply, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 0)
		pidhbox.Add(self.stepresp, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 5)

		sizer2j = wx.StaticBoxSizer(limbox,wx.VERTICAL)
		#lims0.Add(kp_l, 0, wx.ADJUST_MINSIZE|wx.RIGHT, 10)
		#lims0.Add(kp_l, 0, wx.ADJUST_MINSIZE|wx.LEFT, 10)
		lims0.Add(kp_l, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 12)
		lims0.Add(ki_l, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 12)
		lims0.Add(kd_l, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 12)

		lims1.Add(self.kps, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 14)
		lims1.Add(self.kis, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 14)
		lims1.Add(self.kds, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 14)

		lims2.Add(self.pdecade, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 1)
		lims2.Add(self.idecade, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 1)
		lims2.Add(self.ddecade, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 1)

		lims3.Add(pidhbox, 0, wx.ADJUST_MINSIZE|wx.LEFT, 15)

		sizer2j.Add(lims0, 0, wx.ADJUST_MINSIZE|wx.ALIGN_CENTRE|wx.ALL, 5)
		sizer2j.Add(lims1, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		sizer2j.Add(lims2, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.RIGHT, 5)
		sizer2j.Add(lims3, 0, wx.ADJUST_MINSIZE|wx.ALL, 5)
		sizer2j2 = wx.BoxSizer(wx.HORIZONTAL)
		sizer2j2.Add(sizer2j, 0, wx.ADJUST_MINSIZE|wx.LEFT|wx.CENTER, 10)
		self.kps.Bind(wx.EVT_SLIDER,self.OnKPAdjust)
		self.kis.Bind(wx.EVT_SLIDER,self.OnKIAdjust)
		self.kds.Bind(wx.EVT_SLIDER,self.OnKDAdjust)
		self.pdecade.Bind(wx.EVT_CHOICE,self.OnKPAdjust)
		self.idecade.Bind(wx.EVT_CHOICE,self.OnKIAdjust)
		self.ddecade.Bind(wx.EVT_CHOICE,self.OnKDAdjust)
		self.gainapply.Bind(wx.EVT_BUTTON, self.OnGainApply)
		self.stepresp.Bind(wx.EVT_TOGGLEBUTTON, self.OnStepResp)

		grid_sizer_2.Add(sizer2a, 1, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, self.TOP_SPACE + 10)
		grid_sizer_2.Add(sizer2h2, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, self.TOP_SPACE + 10)
		grid_sizer_2.Add(sizer2b, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, 5)
		grid_sizer_2.Add(sizer2i2, 0, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, 5)
		grid_sizer_2.Add(sizer2g, 1, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, 5)
		grid_sizer_2.Add(sizer2j2, 1, wx.ADJUST_MINSIZE|wx.GROW|wx.TOP, 5)
		grid_sizer_2.Add(self.panel_12, 0, wx.LEFT|wx.ADJUST_MINSIZE|wx.GROW, 5)


		self.offsetfig = Figure((6,5), 75)
		self.offsetcanvas = FigureCanvasWxAgg(self, -1, self.offsetfig)
		grid_sizer_3 = wx.FlexGridSizer(1, 2, 0, 0)
		grid_sizer_3.Add(grid_sizer_2, 1, wx.ADJUST_MINSIZE|wx.GROW|wx.ALL, 5)
		grid_sizer_3.Add(self.offsetcanvas, 1, wx.ADJUST_MINSIZE|wx.CENTRE|wx.ALL, 35)
		self.x=0.0;self.y=0.0

		self.subplot = self.offsetfig.add_subplot(111)
		self.scalebar=[None,None]
		xext = 10*self.ANG_PER_VOLT_X*self.SCAN_GAIN; yext = 10*self.ANG_PER_VOLT_Y*self.SCAN_GAIN
		self.im = self.subplot.imshow(n.zeros((500,500)),cmap=cm.gray,vmin=-1,vmax=0,origin='lower',extent=[-xext,xext,-yext,yext])
		self.subplot.set_xlabel(r'X Offset ($\AA$)')
		self.subplot.set_ylabel(r'Y Offset ($\AA$)')
		#self.horiz1 = 1000; self.horiz2 = 2000; self.vert1 = 1000; self.vert2 = 2000
		self.subplot.axhline(y=0, xmin=0.05, xmax=0.95,linewidth=1, color='#333333')
		self.horiz1 = self.subplot.axhline(y=1000, xmin=0.05, xmax=0.95,linewidth=1, color='#8899bb')
		self.horizn1 = self.subplot.axhline(y=-1000, xmin=0.05, xmax=0.95,linewidth=1, color='#8899bb')
		self.horiz2 = self.subplot.axhline(y=2000, xmin=0.05, xmax=0.95,linewidth=1, color='#ddeeff')
		self.horizn2 = self.subplot.axhline(y=-2000, xmin=0.05, xmax=0.95,linewidth=1, color='#ddeeff')
		self.subplot.axvline(x=0, ymin=0.05, ymax=0.95,linewidth=1, color='#333333')
		self.vert1 = self.subplot.axvline(x=1000, ymin=0.05, ymax=0.95,linewidth=1, color='#8899bb')
		self.vertn1 = self.subplot.axvline(x=-1000, ymin=0.05, ymax=0.95,linewidth=1, color='#8899bb')
		self.vert2 = self.subplot.axvline(x=2000, ymin=0.05, ymax=0.95,linewidth=1, color='#ddeeff')
		self.vertn2 = self.subplot.axvline(x=-2000, ymin=0.05, ymax=0.95,linewidth=1, color='#ddeeff')
		# Note that event is a MplEvent
		self.offsetcanvas.mpl_connect('motion_notify_event', self.UpdateOffsets)
		self.offsetcanvas.Bind(wx.EVT_LEFT_DOWN, self.ChangeOffsets)

		#grid_sizer_2.Add(self.imagebox, 0, wx.LEFT|wx.ADJUST_MINSIZE|wx.GROW, 5)
		grid_sizer_1.Add(grid_sizer_3, 1, wx.GROW, 0)
		sizer_1.Add(grid_sizer_1, 1, wx.GROW, 0)
		self.SetAutoLayout(True)
		self.SetSizer(sizer_1)
		sizer_1.Fit(self)
		sizer_1.SetSizeHints(self)
		#self.Layout()

	def UpdateOffsets(self, event):
		'''
		This function displays the xy coordinates in the statusbar. Needs to be outside the
		tab-level class because status bars are not unique to individual tabs.
		'''
		if event.inaxes:
			self.x, self.y = event.xdata, event.ydata
			self.x = int(round(self.x))
			self.y = int(round(self.y))
			infostr = "x= "+str(self.x)[:5]+"  y="+str(self.y)[:5]
			self.statusBar.SetStatusText((infostr),0)

	def ChangeOffsets(self,event):
		# Set image extents #
		xhv_gain = self.newtree.treebytreename['presets'].data['Gains'][createtree.sv.GAIN_XHV[2]][0]
		yhv_gain = self.newtree.treebytreename['presets'].data['Gains'][createtree.sv.GAIN_YHV[2]][0]
		xext = 10*self.ANG_PER_VOLT_X*self.SCAN_GAIN*xhv_gain; yext = 10*self.ANG_PER_VOLT_Y*self.SCAN_GAIN*yhv_gain
		xext1 = self.im.get_extent()[1]
		yext1 = self.im.get_extent()[3]
		if xext != xext1:
			self.im.set_extent([-xext,xext,-yext1,yext1])
			dig2 = len(str(int(xext)))-1
			dig1 = len(str(int(xext/2.)))-1
			self.vert1.set_xdata([round(xext/2.,-dig1),round(xext/2.,-dig1)])
			self.vertn1.set_xdata([-round(xext/2.,-dig1),-round(xext/2.,-dig1)])
			self.vert2.set_xdata([round(xext/1.,-dig2),round(xext/1.,-dig2)])
			self.vertn2.set_xdata([-round(xext/1.,-dig2),-round(xext/1.,-dig2)])
		xext1 = self.im.get_extent()[1]
		if yext != yext1:
			self.im.set_extent([-xext1,xext1,-yext,yext])
			dig2 = len(str(int(yext)))-1
			dig1 = len(str(int(yext/2.)))-1
			self.horiz1.set_ydata([round(yext/2.,-dig1),round(yext/2.,-dig1)])
			self.horizn1.set_ydata([-round(yext/2.,-dig1),-round(yext/2.,-dig1)])
			self.horiz2.set_ydata([round(yext/1.,-dig2),round(yext/1.,-dig2)])
			self.horizn2.set_ydata([-round(yext/1.,-dig2),-round(yext/1.,-dig2)])

		width = self.newtree.treebytreename['image'].data['Image Size']['phys x'][0]
		height = self.newtree.treebytreename['image'].data['Image Size']['phys y'][0]
		xy = (self.x-(width/2.), self.y-(height/2.))
		self.SaveValue('presets','Offsets','x off',self.x)
		if self.param_grid.GetCellValue(0,0) == 'x off': self.param_grid.SetCellValue(0,1,str(self.x))
		self.SaveValue('presets','Offsets','y off',self.y)
		if self.param_grid.GetCellValue(1,0) == 'y off': self.param_grid.SetCellValue(1,1,str(self.y))

		if hasattr(self,'offsetrect'): self.offsetrect.remove()
		self.offsetrect = matplotlib.patches.Rectangle(xy, width, height, facecolor='orange', edgecolor='w')
		self.offsetfig.gca().add_patch(self.offsetrect)
		self.offsetcanvas.draw()

	def OnYes(self,event): self.sendEnter(event,arg='y')
	def OnNo(self,event):
		self.sendEnter(event,arg='n')
		if hasattr(self,'manualapp'):
			self.manualapp.Close(True)
			self.manualapp = None
	def OnAbort(self,event):
		self.sendEnter(event,arg='abort')
		if hasattr(self,'manualapp'):
			self.manualapp.Close(True)
			self.manualapp = None
	def OnConn_b(self,event): self.OnConn(event,str(self.stm_choice.GetValue()))
	def OnSTMCh(self,event): self.stm_choice.SetValue(self.stm_controllers[str(self.stm_list.GetStringSelection())])
	
	def setTime(self):
		'''
		Sets the time remaining in the LED widget.
		'''
		if self.scanparams:
			lines = self.scanparams.SCAN_Y[0] - self.lineN
			minutes = str(int((self.sd.avgt*lines) / 60))
			seconds = str(int((self.sd.avgt*lines) % 60))
			if len(seconds) == 1: seconds = '0'+seconds
			time = minutes+':'+seconds
			self.timeleft.SetValue(time)
		else: pass
	
	def OnTimer(self, event):
		'''
		Updates the line number and time left LEDs. Runs on a timer.
		'''
		if self.lineq.empty(): pass
		else: self.lineN = self.lineq.get()
		self.lineled.SetValue(str(self.lineN))
		self.setTime()
			
	
	def CalcPhys(self,tree,branch):
		'''
		Calculates the physical units of the scan
		from DAC units.
		'''
		if 'alpha' in self.newtree.treebytreename[tree].data[branch]: ## calculate the rc decay time and update
			alpha = self.newtree.treebytreename['image'].data['Image Parameters']['alpha'][0]
			rc_decay = ((-1/n.log(1-alpha))/ws.SERVO_FREQ)*1e6
			if 'rc time' in self.newtree.treebytreename[tree].data[branch]:
				count = 0
				key = ''
				while key != 'rc time':
					key = self.param_grid.GetCellValue(count,0)
					count += 1
				self.param_grid.SetCellValue(count-1,1,str(int(rc_decay)))
		if 'phys y' or 'yhv gain' in self.newtree.treebytreename[tree].data[branch]: ## calculate the physical dimensions of the image
			#if 'phys x' in self.newtree.treebytreename[tree].data[branch]:
				dac_step = self.newtree.treebytreename['image'].data['Image Size']['dac step'][0]
				dac_avgs = self.newtree.treebytreename['image'].data['Image Size']['dac avgs'][0]
				max_rate = self.newtree.treebytreename['image'].data['Image Size']['max rate'][0]
				xhv_gain = self.newtree.treebytreename['image'].data['Gains'][createtree.sv.GAIN_XHV[2]][0]
				yhv_gain = self.newtree.treebytreename['image'].data['Gains'][createtree.sv.GAIN_YHV[2]][0]
				max_rate_p = max_rate/(self.VOLTS_PER_ADU*self.ANG_PER_VOLT_X*self.SCAN_GAIN*xhv_gain)
				if not max_rate_p < ws.XMAX_RATE: max_rate_p = ws.XMAX_RATE
				scan_y = self.newtree.treebytreename['image'].data['Image Size']['scan y'][0]
				n_reads = self.newtree.treebytreename['image'].data['Image Parameters'][createtree.sv.N_READS[2]][0]
				point_delay = self.newtree.treebytreename['image'].data['Image Parameters'][createtree.sv.POINT_DELAY[2]][0]
				scan_delay = self.newtree.treebytreename['image'].data['Image Parameters'][createtree.sv.SCAN_DELAY[2]][0]
				line_delay = self.newtree.treebytreename['image'].data['Image Parameters'][createtree.sv.LINE_DELAY[2]][0]
				if max_rate_p != 0: rate_delay = (1./max_rate_p)
				else: rate_delay = (1/1000.)
				phys_y = dac_step*dac_avgs*scan_y*self.VOLTS_PER_ADU*self.ANG_PER_VOLT_Y*self.SCAN_GAIN*yhv_gain
				count = 0
				key = ''
				dac_step = self.newtree.treebytreename['image'].data['Image Size']['dac step'][0]
				dac_avgs = self.newtree.treebytreename['image'].data['Image Size']['dac avgs'][0]
				scan_x = self.newtree.treebytreename['image'].data['Image Size']['scan x'][0]
				phys_x = dac_step*dac_avgs*scan_x*self.VOLTS_PER_ADU*self.ANG_PER_VOLT_X*self.SCAN_GAIN*xhv_gain
				scan_rate = phys_x/(float((n_reads*ws.READ_TIME+point_delay+rate_delay*dac_step)*scan_x*dac_avgs))
				phys_step = phys_x/scan_x
				
				est_time = 2*scan_y*(scan_x*dac_avgs*(n_reads*ws.READ_TIME+point_delay)+(phys_x/max_rate_p)+line_delay*10.e-3)+scan_delay*10.e-3
				est_time /= 60
				
				self.SaveValue('image','Image Size',createtree.sv.PHYS_Y[2],phys_y)
				self.SaveValue('image','Image Size',createtree.sv.PHYS_X[2],phys_x)
				self.SaveValue('image','Image Size',createtree.sv.PHYS_STEP[2],phys_step)
				self.SaveValue('image','Image Size',createtree.sv.SCAN_RATE[2],scan_rate)
				self.SaveValue('image','Image Size',createtree.sv.EST_TIME[2],est_time)

				if 'phys y' in self.newtree.treebytreename[tree].data[branch]:
					count = 0
					key = ''
					while key != 'phys y':
						key = self.param_grid.GetCellValue(count,0)
						count += 1
					self.param_grid.SetCellValue(count-1,1,str(int(phys_y)))
				if 'phys x' in self.newtree.treebytreename[tree].data[branch]:
					while key != 'phys x':
						key = self.param_grid.GetCellValue(count,0)
						count += 1
						if count > 10: break
					self.param_grid.SetCellValue(count-1,1,str(int(phys_x)))
				if 'phys step' in self.newtree.treebytreename[tree].data[branch]:
					while key != 'phys step':
						key = self.param_grid.GetCellValue(count,0)
						count += 1
						if count > 10: break
					self.param_grid.SetCellValue(count-1,1,str(phys_step)[0:4])
				if 'scan rate' in self.newtree.treebytreename[tree].data[branch]:
					while key != 'scan rate':
						key = self.param_grid.GetCellValue(count,0)
						count += 1
						if count > 10: break
					self.param_grid.SetCellValue(count-1,1,str(scan_rate)[0:6])
				if 'est time' in self.newtree.treebytreename[tree].data[branch]:
					while key != 'est time':
						key = self.param_grid.GetCellValue(count,0)
						count += 1
						if count > 10: break
					self.param_grid.SetCellValue(count-1,1,str(est_time)[0:6])
	
	def OnGridClick(self,event):
		'''
		Sets the cursor and enables editing control once the grid is clicked.
		'''
		self.param_grid.SetGridCursor(event.GetRow(),event.GetCol())
		self.param_grid.EnableCellEditControl()
	
	def OnChange(self, event):
		'''
		Once a grid value is changed, this function is called to save
		the variable in the tree class and re-calculate the physical dimensions
		of the image if necessary.
		'''
		tree = self.last['tree']
		branch = self.last['branch']
		if self.last['twig'] != None:
			twig = self.last['twig']
			self.CheckValue(tree,twig,self.param_grid.GetCellValue(0,1),0,1)
			value = self.param_grid.GetCellValue(i,1)
			self.SaveValue(tree,branch,twig,value)
		else:
			for i in range(10):
				twig = self.param_grid.GetCellValue(i,0)
				if twig == '': break
				self.CheckValue(tree,twig,self.param_grid.GetCellValue(i,1),i,1)
				value = self.param_grid.GetCellValue(i,1)
				self.SaveValue(tree,branch,twig,value)
			self.CalcPhys(tree,branch)
			if 'x off' or 'scan y' in self.newtree.treebytreename[tree].data[branch]:
				self.x = self.newtree.treebytreename['presets'].data['Offsets']['x off'][0]
				self.y = self.newtree.treebytreename['presets'].data['Offsets']['y off'][0]
				self.ChangeOffsets(None)

	def OnKPAdjust(self,event):
		exec 'val = %d%s'%(self.kps.GetValue(),self.pdecade.GetStringSelection())
		self.SaveValue('pid','Gains','pgain',val)
		if self.param_grid.GetCellValue(3,0) == 'pgain': self.param_grid.SetCellValue(3,1,str(val))

	def OnKIAdjust(self,event):
		exec 'val = %d%s'%(self.kis.GetValue(),self.idecade.GetStringSelection())
		self.SaveValue('pid','Gains','igain',val)
		if self.param_grid.GetCellValue(4,0) == 'igain': self.param_grid.SetCellValue(4,1,str(val))

	def OnKDAdjust(self,event):
		exec 'val = %d%s'%(self.kds.GetValue(),self.ddecade.GetStringSelection())
		self.SaveValue('pid','Gains','dgain',val)
		if self.param_grid.GetCellValue(5,0) == 'dgain': self.param_grid.SetCellValue(5,1,str(val))

	def OnActivate(self, event):
		'''
		Does stuff.
		'''
		child = event.GetItem()
		parent = self.param_tree.GetItemParent(child)
		if parent in self.newtree.branchids:
			tree = self.param_tree.GetItemParent(parent)
			self.last['tree'] = self.param_tree.GetItemText(tree)
			self.last['branch'] = self.param_tree.GetItemText(parent)
			self.last['twig'] = self.param_tree.GetItemText(child)
			self.param_grid.ClearGrid()
			self.newtree.setTwig(self.param_grid,child,parent)
		else: pass
		event.Skip()

	def OnExpand(self, event):
		'''
		Sets tree items in the grid once a branch is expanded.
		'''
		child = event.GetItem()
		parent = self.param_tree.GetItemParent(child)
		if str(self.param_tree.GetItemText(self.param_tree.GetItemParent(child))) == 'Root':
			self.stm_selected.SetLabel('Selected Scan: '+self.param_tree.GetItemText(child))
		elif str(self.param_tree.GetItemText(self.param_tree.GetItemParent(parent))) == 'Root':
			self.stm_selected.SetLabel('Selected Scan: '+self.param_tree.GetItemText(parent))
		if child in self.newtree.branchids:
			self.last['tree'] = self.param_tree.GetItemText(parent)
			self.last['branch'] = self.param_tree.GetItemText(child)
			self.last['twig'] = None
			branch = self.param_tree.GetItemText(child)
			self.newtree.setBranch(self.param_grid,child)
			if self.last['branch']=='Image Size':self.CalcPhys(self.last['tree'],self.last['branch'])
		#elif parent == self.newtree.treeroot:
			#collapse = self.newtree.treeids
			#collapse.remove(child)
			#for tree in collapse:
				#self.param_tree.Collapse(tree)
		else:
			self.param_grid.ClearGrid()
			self.newtree.clearLast(self.param_grid)
		event.Skip()

	def OnCollapse(self, event):
		'''
		If a branch is collapsed, the grid gets cleared.
		'''
		child = event.GetItem()
		parent = self.param_tree.GetItemParent(child)
		if child in self.newtree.branchids:
			self.last['tree'] = self.param_tree.GetItemText(parent)
			self.last['branch'] = self.param_tree.GetItemText(child)
			self.last['twig'] = None
			branch = self.param_tree.GetItemText(child)
			self.newtree.setBranch(self.param_grid,child)
		else:
			self.param_grid.ClearGrid()
			self.newtree.clearLast(self.param_grid)
		event.Skip()

	def SaveValue(self, tree, branch, twig, value):
		'''
		Stores a changed value into the tree class.
		'''
		oldvalue = self.newtree.treebytreename[tree].data[branch][twig][0]
		if type(oldvalue) == int:
			try:
				value = int(value)
				self.newtree.treebytreename[tree].data[branch][twig][0] = value
			except: pass
		elif type(oldvalue) == float:
			try:
				value = float(value)
				self.newtree.treebytreename[tree].data[branch][twig][0] = value
			except: pass
		elif type(oldvalue) == str:
			try:
				value = str(value)
				self.newtree.treebytreename[tree].data[branch][twig][0] = value
			except: pass
		else: pass
	
	def CheckValue(self, tree, twig, value, xloc, yloc):
		'''
		Checks if a grid value is within the allowed limits.
		'''
		limits = self.newtree.treebytreename[tree].limits
		if twig in limits:
			if '.' in value: value = float(value)
			else: value = int(value)
			if limits[twig][0] <= value <= limits[twig][1]:
				pass
			elif value < limits[twig][0]:
				value = limits[twig][0]
			else: value = limits[twig][1]
		else: pass
		self.param_grid.SetCellValue(xloc,yloc,str(value))

class MyFrame(wx.Frame,MenuItems,Scanning2):
	''' Creates the frame and notebook for the created panels. '''
	def __init__(self, *args, **kwds):
		kwds["style"] = wx.DEFAULT_FRAME_STYLE
		wx.Frame.__init__(self, None, -1, "", pos=(0, 0),size=ws.DEFAULT_SIZE, style=wx.DEFAULT_FRAME_STYLE)
		MenuItems.__init__(self)
		self.nb = wx.Notebook(self)
		self.panel = STMControl(self.nb)
		self.nb.AddPage(self.panel,"Control")
		self.editor=Editor(self,self.nb)
		self.nb.AddPage(self.editor,'Editor')
		self.SetTitle("STM Client")
		Scanning2.__init__(self,self.nb,dataq=self.panel.dataq,specq=self.panel.ivq,offset=(self.panel.offsetfig,self.panel.offsetcanvas))
		self.panel.statusBar = self.statusBar

class MyApp(wx.App):
	def OnInit(self):
		wx.InitAllImageHandlers()
		frame_1 = MyFrame()
		self.SetTopWindow(frame_1)
		frame_1.Show()
		return 1

# end of class MyApp

if __name__ == "__main__":
	app = MyApp(0)
	app.MainLoop()
